#include "aht20.h"


#define AHT_ADDR 	(0x38<<1)		//设备iic地址，如果手册提供的是七位设备地址，需左移一位 (0x6D<<1)



mI2CTypedef_t AHTI2c;			//io模拟i2c接口

static void i2c_Delay(void){
//	__NOP();__NOP();__NOP();__NOP();__NOP();
//	__NOP();__NOP();__NOP();__NOP();__NOP();
}

static void i2c_SdaH(void){
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET);
}

static void i2c_SdaL(void){
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET);
}

static void i2c_SclH(void){
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}

static void i2c_SclL(void){
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}

static u8 i2c_ReadSda(void){
	return HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5);
}

static u8 i2c_ReadScl(void){
	return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
}

void aht_i2c_init(mI2CTypedef_t *i2c){
	i2c->IIC_InitPort=0;
	i2c->IIC_Delay=i2c_Delay;
	i2c->IIC_SDA_H=i2c_SdaH;
	i2c->IIC_SDA_L=i2c_SdaL;
	i2c->IIC_SCL_H=i2c_SclH;
	i2c->IIC_SCL_L=i2c_SclL;
	i2c->IIC_READ_SDA=i2c_ReadSda;
	i2c->IIC_READ_SCL=i2c_ReadScl;
}

//从uWriteAddress地址开始写入len字节数据					//通常情况下可以这样读写，但是顶不住有些设备与众不同，所以具体读写时序还要看芯片手册
void aht_i2c_write(u8 uWriteAddress,u8 *buf,u8 len)
{
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_WR);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,(uWriteAddress) & 0xFF);
	i2c_WaitAck(&AHTI2c);
	while(len--){
		i2c_SendByte(&AHTI2c,*buf++);
		i2c_WaitAck(&AHTI2c);
	}
	i2c_Stop(&AHTI2c);
}
//从uWriteAddress地址开始读出len字节数据
u8 aht_i2c_read(u8 uReadAddress,u8 *buf,u8 len)
{
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_WR);
	if(1==i2c_WaitAck(&AHTI2c)){	//ERROR
		goto ERR;
	}
	i2c_SendByte(&AHTI2c,uReadAddress);
	if(1==i2c_WaitAck(&AHTI2c)){	//ERROR
		goto ERR;
	}
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_RD);
	if(1==i2c_WaitAck(&AHTI2c)){	//ERROR
		goto ERR;
	}
	while(len-->1){
		*buf++ = i2c_ReadByte(&AHTI2c);
		i2c_Ack(&AHTI2c);
	}
	*buf++ = i2c_ReadByte(&AHTI2c);
	i2c_NAck(&AHTI2c);
	i2c_Stop(&AHTI2c);
	return 1;//正常返回
ERR:
	i2c_SdaErrorClear(&AHTI2c);
	return 0;	
}

//CRC校验类型：CRC8/MAXIM
//多项式：X8+X5+X4+1
//Poly：0011 0001  0x31
//高位放到后面就变成 1000 1100 0x8c
//C现实代码：
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num)
{
	uint8_t i;
	uint8_t byte;
	uint8_t crc=0xFF;
	for(byte=0; byte<Num; byte++)
	{
		crc^=(message[byte]);
		for(i=8; i>0; --i)
		{
			if(crc&0x80) crc=(crc<<1)^0x31;
			else crc=(crc<<1);
		}
	}
	return crc;
}

u8 AHT20_Read_Status(void)//读取状态寄存器
{
	uint8_t Byte_first;
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_RD);
	i2c_WaitAck(&AHTI2c);
	Byte_first = i2c_ReadByte(&AHTI2c);
	i2c_NAck(&AHTI2c);
	i2c_Stop(&AHTI2c);
	return Byte_first;
}
uint8_t AHT20_Read_Cal_Enable(void)  //查询cal enable位有没有使能
{
	uint8_t val = 0;//ret = 0,
	val = AHT20_Read_Status();
	if((val & 0x68)==0x08)
		return 1;
	else  return 0;
}
void AHT20_SendAC(void) //向AHT20发送AC命令
{
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_WR);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0xac);//0xAC采集命令
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x33);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x00);
	i2c_WaitAck(&AHTI2c);
	i2c_Stop(&AHTI2c);
}
void AHT20_Read_CTdata_crc(uint32_t *ct) //CRC校验后，读取AHT20的温度和湿度数据
{
	volatile uint8_t  Byte_1th=0;
	volatile uint8_t  Byte_2th=0;
	volatile uint8_t  Byte_3th=0;
	volatile uint8_t  Byte_4th=0;
	volatile uint8_t  Byte_5th=0;
	volatile uint8_t  Byte_6th=0;
	volatile uint8_t  Byte_7th=0;
	uint32_t RetuData = 0;
	uint16_t cnt = 0;
	uint8_t  CTDATA[6]= {0}; //用于CRC传递数组

	AHT20_SendAC();//向AHT10发送AC命令
	delay_ms(80);//延时80ms左右
	cnt = 0;
	while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0，表示为空闲状态，若为1，表示忙状态
	{
		delay_ms(2);
		if(cnt++>=100)
		{
			break;
		}
	}

	i2c_Start(&AHTI2c);

	i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_RD);
	i2c_WaitAck(&AHTI2c);
	CTDATA[0]=Byte_1th = i2c_ReadByte(&AHTI2c);//状态字，查询到状态为0x98,表示为忙状态，bit[7]为1；状态为0x1C，或者0x0C，或者0x08表示为空闲状态，bit[7]为0
	i2c_Ack(&AHTI2c);
	CTDATA[1]=Byte_2th = i2c_ReadByte(&AHTI2c);//湿度
	i2c_Ack(&AHTI2c);
	CTDATA[2]=Byte_3th = i2c_ReadByte(&AHTI2c);//湿度
	i2c_Ack(&AHTI2c);
	CTDATA[3]=Byte_4th = i2c_ReadByte(&AHTI2c);//湿度/温度
	i2c_Ack(&AHTI2c);
	CTDATA[4]=Byte_5th = i2c_ReadByte(&AHTI2c);//温度
	i2c_Ack(&AHTI2c);
	CTDATA[5]=Byte_6th = i2c_ReadByte(&AHTI2c);//温度
	i2c_Ack(&AHTI2c);
	Byte_7th = i2c_ReadByte(&AHTI2c);//CRC数据
	i2c_NAck(&AHTI2c);                           //注意: 最后是发送NAK
	i2c_Stop(&AHTI2c);

	if(Calc_CRC8(CTDATA,6)==Byte_7th)
	{
		RetuData = (RetuData|Byte_2th)<<8;
		RetuData = (RetuData|Byte_3th)<<8;
		RetuData = (RetuData|Byte_4th);
		RetuData =RetuData >>4;
		ct[0] = RetuData;//湿度
		RetuData = 0;
		RetuData = (RetuData|Byte_4th)<<8;
		RetuData = (RetuData|Byte_5th)<<8;
		RetuData = (RetuData|Byte_6th);
		RetuData = RetuData&0xfffff;
		ct[1] =RetuData; //温度

	}
	else
	{
		ct[0]=0xFFFF;
		ct[1]=0xFFFF;//校验错误返回值，客户可以根据自己需要更改
	}//CRC数据
}

void JH_Reset_REG(uint8_t addr)
{

	uint8_t Byte_first,Byte_second,Byte_third;
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x70);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,addr);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x00);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x00);
	i2c_WaitAck(&AHTI2c);
	i2c_Stop(&AHTI2c);

	delay_ms(5);//延时5ms左右
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x71);
	i2c_WaitAck(&AHTI2c);
	Byte_first = i2c_ReadByte(&AHTI2c);
	i2c_Ack(&AHTI2c);
	Byte_second = i2c_ReadByte(&AHTI2c);
	i2c_Ack(&AHTI2c);
	Byte_third = i2c_ReadByte(&AHTI2c);
	i2c_NAck(&AHTI2c);   
	i2c_Stop(&AHTI2c);

	delay_ms(10);//延时10ms左右
	i2c_Start(&AHTI2c);
	i2c_SendByte(&AHTI2c,0x70);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,0xB0|addr);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,Byte_second);
	i2c_WaitAck(&AHTI2c);
	i2c_SendByte(&AHTI2c,Byte_third);
	i2c_WaitAck(&AHTI2c);
	i2c_Stop(&AHTI2c);

	Byte_second=0x00;
	Byte_third =0x00;
}

void AHT20_Start_Init(void)
{
	JH_Reset_REG(0x1b);
	JH_Reset_REG(0x1c);
	JH_Reset_REG(0x1e);
}



void aht_init(void)
{
	aht_i2c_init(&AHTI2c);
	delay_ms(100);	//等待芯片就绪
	if((AHT20_Read_Status()&0x18)!=0x18)
	{
		AHT20_Start_Init(); //重新初始化寄存器
		delay_ms(10);
	}
	
}
//较长阻塞
void aht_read_data(u8 *buf)  
{
	uint32_t CT_data[2];
	u16 humi,temp;
	AHT20_Read_CTdata_crc(CT_data);  //crc校验后，读取AHT20的温度和湿度数据
	if(CT_data[0]==0xffff&&CT_data[1]==0xffff){
		humi =0;
		temp =0;
	}
	else{
		humi =CT_data[0]*100*10/1024/1024;  //计算得到湿度值c1（放大了10倍）
		temp =CT_data[1]*200*10/1024/1024-500;//计算得到温度值t1（放大了10倍）
	}
	buf[0]=temp>>8;	//温度高
	buf[1]=temp;	//温度低
	buf[2]=humi>>8;	//湿度高
	buf[3]=humi;	//湿度低
	
}

//由于例程提供的温湿度读取阻塞时间很长，重写一个阻塞少的
void Task_aht(void)
{
	static u8 sta=0;
	
	volatile uint8_t  Byte_1th=0;
	volatile uint8_t  Byte_2th=0;
	volatile uint8_t  Byte_3th=0;
	volatile uint8_t  Byte_4th=0;
	volatile uint8_t  Byte_5th=0;
	volatile uint8_t  Byte_6th=0;
	volatile uint8_t  Byte_7th=0;
	uint32_t RetuData = 0;
	uint8_t  CTDATA[6]= {0}; //用于CRC传递数组
	double humi,temp;
	
	static uint32_t ticks_old=0;
	if(time_before(Ticks_Num_1Ms,ticks_old+TIMEOUT_MS(100)))	return;
	ticks_old=Ticks_Num_1Ms;
	
	switch(sta){
		case 0:{
			AHT20_SendAC();//向AHT10发送AC命令
			sta++;
		}break;
		case 1:{
			if((AHT20_Read_Status()&0x80)==0x00){
				sta++;
			}
		}break;
		case 2:{
			i2c_Start(&AHTI2c);
			i2c_SendByte(&AHTI2c,AHT_ADDR|I2C_RD);
			i2c_WaitAck(&AHTI2c);
			CTDATA[0]=Byte_1th = i2c_ReadByte(&AHTI2c);//状态字，查询到状态为0x98,表示为忙状态，bit[7]为1；状态为0x1C，或者0x0C，或者0x08表示为空闲状态，bit[7]为0
			i2c_Ack(&AHTI2c);
			CTDATA[1]=Byte_2th = i2c_ReadByte(&AHTI2c);//湿度
			i2c_Ack(&AHTI2c);
			CTDATA[2]=Byte_3th = i2c_ReadByte(&AHTI2c);//湿度
			i2c_Ack(&AHTI2c);
			CTDATA[3]=Byte_4th = i2c_ReadByte(&AHTI2c);//湿度/温度
			i2c_Ack(&AHTI2c);
			CTDATA[4]=Byte_5th = i2c_ReadByte(&AHTI2c);//温度
			i2c_Ack(&AHTI2c);
			CTDATA[5]=Byte_6th = i2c_ReadByte(&AHTI2c);//温度
			i2c_Ack(&AHTI2c);
			Byte_7th = i2c_ReadByte(&AHTI2c);//CRC数据
			i2c_NAck(&AHTI2c);                           //注意: 最后是发送NAK
			i2c_Stop(&AHTI2c);
			//CRC数据
			if(Calc_CRC8(CTDATA,6)==Byte_7th)//
			{
				RetuData = (RetuData|Byte_2th)<<8;
				RetuData = (RetuData|Byte_3th)<<8;
				RetuData = (RetuData|Byte_4th);
				RetuData =RetuData >>4;
				humi=RetuData*100.0/1048576;//湿度
				RetuData = 0;
				RetuData = (RetuData|Byte_4th)<<8;
				RetuData = (RetuData|Byte_5th)<<8;
				RetuData = (RetuData|Byte_6th);
				RetuData = RetuData&0xfffff;
				temp=RetuData*200.0/1048576-50;//温度
				
			}
			else
			{
				temp=0;
				humi=0;
			}
			mSystem.temp=temp;
			mSystem.humi=humi;
			sta=0;
		}break;
		
		default:{
			sta=0;
		}break;
	}
}




